<?php

/**
 * 在这里，我们将PermissionGroups中存放的权限组信息与控制器对应，
 * 下面也称为控制器在数据库中的记录
 * 同理，将Permissions中存放的权限信息与控制器方法对应，
 * 下面也称之为控制器方法在数据库中的记录
 * 我们尽可能地保证数据库中的控制器及方法记录与实际文件中的保持一致，并使用方法将它们同步
 */

class Model_PermissionManager {

	/**
	 * 控制器所在目录
	 * @var dir $controller_dir
	 */
	var $controller_dir;
	
	/**
	 * $tb_PerGroups
	 * @var Table_PermissionGroups
	 */
	var $tb_PerGroups;
	
	/**
	 * $tb_Permissions
	 * @var Table_Permissions
	 */
	var $tb_Permissions;
	
	function Model_PermissionManager()
	{
		$this->tb_PerGroups =& FLEA::getSingleton('Table_PermissionGroups');
		$this->tb_Permissions =& FLEA::getSingleton('Table_Permissions');
	}
	
	
	function find_Permissions(){
		$ctrl_files = array_flip($this->_find_Controller_file($this->controller_dir));
		return $this->_find_in_file($ctrl_files);
	}
	
	
	/**
	 * 递归找到指定目录中的全部PHP文件
	 * @param dir $ddir
	 * @param array $ctrl_files
	 * @return array
	 */
	function _find_Controller_file($ddir, $ctrl_files = array())  
	{
		$handle=opendir($ddir);
		
		while ($file = readdir($handle)){
			$bdir = $ddir."/".$file;
			
			// 判断此文件是一个文件夹文件
			if ($file != '.' && $file != '..' && filetype($bdir) == 'dir' ){
				$ctrl_files = $this->_find_Controller_file($ddir."/".$file, $ctrl_files);
			// 还必须是个PHP文件
			}elseif ($file != '.' && $file != '..' && substr(strtolower($file),-3)=='php' ){
				$ctrl_files[] = substr(str_replace($this->controller_dir,'',$ddir."/".$file),1);
			}
		}
		closedir($handle);
		return $ctrl_files;
	}
	
	/**
	 * 找到contrller名称及action名称
	 * @param array $ctrl_files
	 * @return array
	 */
	function _find_in_file($ctrl_files){
		
		foreach ($ctrl_files as $filename=>$value) {
			$matched = '';
			$file_content = file_get_contents($this->controller_dir.$filename);
			
			$ctrl_files[$filename] = array();
			
			// 匹配并保存控制器类名称
			$pattern = '/class\s('.FLEA::getAppInf('controllerAccessor').'_'.substr(str_replace('/','_',$filename),0,-4).')\sextends/i';
			preg_match_all($pattern,$file_content,$matched);
			if(isset($matched[1][0])){
				$ctrl_files[$filename]['permission_group_name'] = strtolower($matched[1][0]);
			}
			
			// 匹配并保存动作方法名称
			$pattern = '/function\s'.FLEA::getAppInf('actionAccessor').'(.+?)\(/';
			preg_match_all($pattern,$file_content,$matched);
			if(isset($matched[1])){
				foreach ($matched[1] as $key=>$value) {
					$ctrl_files[$filename]['permissions'][$key] = array_to_lower(array('pername'=>$ctrl_files[$filename]['permission_group_name'].'_'.$value));
				}
			}
		}
		
		return $ctrl_files;
		
	}

	/**
	 * 保存数组中的全部控制器及控制器方法到数据库
	 * @param array $allconctrlloer
	 * @return int
	 */
	function saveAll_to_db($allcontroller){
		$isok = false;
		foreach ($allcontroller as $value) {
			
			// 检查控制器是否已经存在，如果存在则获取控制器id号
			$currentgroup = $this->tb_PerGroups->find("permission_group_name = '{$value['permission_group_name']}'");
			if($currentgroup){
				$value['permission_group_id'] = $currentgroup['permission_group_id'];
			}
			
			$isok = $this->tb_PerGroups->save($value);
			if(!$isok){break;}
		}
		return $isok;
	}
	
	/**
	 * 从数据库中删除数组中的控制器方法，
	 * 如果删除的是该控制器的全部方法，那么同时也删除该控制器
	 * @param array $allcontroller
	 * @return boolin
	 */
	function removeAll_from_db($allcontroller)
	{
		// 循环
		foreach ($allcontroller as $onecontroller) {
			
			// 循环删除数组中的控制器方法
			foreach ($onecontroller['permissions'] as $value) {
				$this->tb_Permissions->clearLinks();
				$this->tb_Permissions->removeByPkv($value['permission_id']);
			}
			
			// 该控制器还有其他方法吗？如果没有，从数据库中删除该控制器
			if($this->tb_Permissions->findCount("permission_group_id = '{$onecontroller['permission_group_id']}'") == 0 ){
				$this->tb_PerGroups->removeByPkv($onecontroller['permission_group_id']);
			}
			
		}
		
		return $allcontroller;
	}
	
	
	
	/**
	 * 从数据库获得全部permission分组数据
	 * @return array
	 */
	function read_from_db()
	{
		return $this->tb_PerGroups->findAll();
	}
	
	/**
	 * 比对文件中获取的数组和数据库获取的数组，返回文件中发现新增的控制器及控制器方法
	 * @param array $infile
	 * @param array $indb
	 * @return array
	 */
	function new_per_infile($infile, $indb)
	{
		$arr = array();
		
		// 比对控制器是否有新增的
		foreach ($infile as $key=>$onefile) {
		
			// 比对控制器方法是否有新增的（为什么不对比控制器呢，因为如果没有新的方法，控制器本身是没有实际意义的）
			if(isset($onefile['permissions'])){
				foreach ($onefile['permissions'] as $value) {
					if(!find_in_array($value['pername'],$indb)){
						$arr[$key]['permission_group_name'] = $infile[$key]['permission_group_name'];
						$arr[$key]['permissions'][] = $value;
					}
				}
			}
			
		}
		return $arr;
	}
	
	
	/**
	 * 比对文件中获取的数组和数据库中获取的数组，返回数据库中存在但文件中已经删除的控制器方法
	 * @param array $infile
	 * @param array $indb
	 * @return array
	 */
	function per_missing_file($infile, $indb)
	{
		$arr = array();
		
		// 比对控制器是否有新增的
		foreach ($indb as $key=>$onefile) {
		
			// 比对控制器方法是否有新增的（为什么不对比控制器呢，因为如果没有新的方法，控制器本身是没有实际意义的）
			foreach ($onefile['permissions'] as $value) {
				if(!find_in_array($value['pername'],$infile)){
					$arr[$key]['permission_group_id'] = $indb[$key]['permission_group_id'];
					$arr[$key]['permission_group_name'] = $indb[$key]['permission_group_name'];
					$arr[$key]['permissions'][] = $value;
				}
			}
			
		}
		return $arr;
	}
	
	/**
	 * 更新权限组的别名字段
	 * @param array $perGroup
	 * @return boolin
	 */
	function GroupAliasUpdate($perGroup){
		unset($perGroup['permission_group_name']);
		return $this->tb_PerGroups->update($perGroup,false);
	}
	
	/**
	 * 更新权限的别名字段
	 *
	 * @param array $permission
	 * @return boolin
	 */
	function PermissionAliasUpdate($permission){
		unset($permission['pername']);
		return $this->tb_Permissions->update($permission,false);
	}

	
	
	
	
}

?>